package topo;

import game.player.Agent;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;



/**
 * @author Remzi
 * 
 */
public class Topology {

	private String label = null;

	private List<Node> nodes = new ArrayList<Node>();

	private List<Edge> edges = new ArrayList<Edge>();

	private HashMap<Node, LinkedList<Edge>> transitionsFromMap;
	private HashMap<Node, LinkedList<Edge>> transitionsToMap;

	public Topology() {

		transitionsFromMap = new HashMap<Node, LinkedList<Edge>>();
		transitionsToMap = new HashMap<Node, LinkedList<Edge>>();
	}

	public Topology clone() {
		Topology topo;
		try {
			topo = getClass().newInstance();
		} catch (Throwable throwable) {
			System.err.println("Warning: clone of automaton failed!");
			return null;
		}
		topo.setLabel(label);
		HashMap<String, Node> hashmap = new HashMap<String, Node>();
		Node state3;
		for (Iterator<Node> iterator = nodes.iterator(); iterator.hasNext();) {
			Node node = iterator.next();
			state3 = node.copy();
			topo.addNode(state3);

			hashmap.put(String.valueOf(  node.getLabel()) , state3);
		}

		for (Iterator<Node> iterator2 = nodes.iterator(); iterator2.hasNext();) {
			Node state2 = iterator2.next();
			Edge atransition[] = getEdgesFromNode(state2);
			Node state4 = hashmap.get(state2.getLabel());
			for (int i = 0; i < atransition.length; i++) {
				Node state5 = hashmap.get(atransition[i].getTo()
						.getLabel());
				Edge copiedtransition = atransition[i].copy(state4, state5);
				topo.addEdge(copiedtransition);
			}

		}

		return topo;
	}

	public Edge[] getEdgesFromNode(Node node) {
		Edge atransition[] = new Edge[0];
		java.util.List<Edge> list = null;
		if (transitionsFromMap != null)
			list = transitionsFromMap.get(node);
		atransition = list.toArray(new Edge[0]);
		
		if (atransition == null)
			System.err.println(" Transition list is null");
		return atransition;
	}
	public Edge[] getEdgesToNode(Node node) {
		Edge atransition[];
		java.util.List<Edge> list = null;
		if (transitionsToMap != null)
			list = transitionsToMap.get(node);
		atransition = list.toArray(new Edge[0]);
		if (atransition == null)
			System.err.println(" Transition list is null");
		return atransition;
	}

	
	public Edge[] getEdgesFromNodeToNode(Node node, Node node2) {
		Edge atransition[] = getEdgesFromNode(node);
		ArrayList<Edge> arraylist = new ArrayList<Edge>();
		for (int i = 0; i < atransition.length; i++)
			if (atransition[i].getTo().equals(node2))
				arraylist.add(atransition[i]);

		return arraylist.toArray(new Edge[0]);
	}

	public void addNode(Node node) {
		nodes.add(node);
		transitionsFromMap.put(node, new LinkedList<Edge>());
		transitionsToMap.put(node, new LinkedList<Edge>());
		
	}

	public void removeEdge(Edge transition) {
		edges.remove(transition);

		java.util.List<Edge> list = transitionsFromMap
				.get(transition.getFrom());
		list.remove(transition);

		list = transitionsToMap.get(transition.getTo());
		list.remove(transition);

	}

	public void removeNode(Node node) {
		Edge atransition[] = getEdgesFromNode(node);
		for (int i = 0; i < atransition.length; i++)
			removeEdge(atransition[i]);

		transitionsFromMap.remove(node);
		transitionsToMap.remove(node);
		nodes.remove(node);
	}

	public void setNodes(List<Node> stateler) {
		this.nodes = stateler;
	}

	public void setEdges(List<Edge> stfler) {
		this.edges = stfler;
	}
	
	public Integer[] connectedNodeIDs(Node node){
		
		Vector<Integer> neighList = new Vector<Integer>();
		Edge[] neigh1 = getEdgesFromNode(node);
		if (neigh1 != null)
			for (int j = 0; j < neigh1.length; j++) {
				neighList.add( neigh1[j].getTo().getLabel() );
			}
		/*Edge[] neigh2= getEdgesToNode(node);
		if (neigh2 != null)
			for (int j = 0; j < neigh2.length; j++) {
				neighList.add( neigh2[j].getFrom().getLabel() );
			}*/
		return neighList.toArray(new Integer[0]);
	}

	public void addEdge(Edge transition) {
		Node node1 = transition.getFrom();
		Node node2 = transition.getTo();
		// if there is any connection between the nodes
		if (getEdgesFromNodeToNode(node1, node2).length > 0) 
			return;
		
		edges.add(transition);
		java.util.List<Edge> list1 = transitionsFromMap.get(node1);
		list1.add(transition);
		java.util.List<Edge> list2 = transitionsToMap.get(node2);
		list2.add(transition);
	
	}

	public int getNodeOutDegree(Node node) {
		return ( getEdgesFromNode(node).length + getEdgesToNode(node).length)/2 ;
	}

	public boolean isNeighbor(Node node1, Node node2) {
		if (getEdgesFromNodeToNode(node1, node2).length == 0)
			return false;
		else
			return true;
	}

	public Node[] getNodeArray() {
		return nodes.toArray(new Node[0]);
	}

	public List<Node> getNodes() {
		return nodes;
	}

	public Edge[] getEdgeArray() {
		return edges.toArray(new Edge[0]);
	}

	public List<Edge> getEdges() {
		return edges;
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public String toString() {
		StringBuffer stringbuffer = new StringBuffer();
		stringbuffer.append(super.toString());
		stringbuffer.append('\n');
		List states = getNodes();
		for (int i = 0; i < states.size(); i++) {
			stringbuffer.append((Node) states.get(i));
			stringbuffer.append('\n');
			Edge atransition[] = getEdgesFromNode((Node) states.get(i));
			for (int j = 0; j < atransition.length; j++) {
				stringbuffer.append('\t');
				stringbuffer.append(atransition[j]);
				stringbuffer.append('\n');
			}

		}

		return stringbuffer.toString();
	}

	public Node getStateByName(int stateLabel) {
		for (int i = 0; i < getNodes().size(); i++)
			if (((Node) getNodes().get(i)).getLabel() == stateLabel)
				return ((Node) getNodes().get(i));
		System.err.println("There is no such node in the node list");
		return null;
	}
	public Vector<int[]> getInterconnectivityMatrix(Vector<Agent> agents){
		Iterator<Node> iternode = nodes.iterator();
		Iterator iteragent = agents.iterator();
		Map< Node, Agent> MapNodeToAgent =new HashMap<Node, Agent>();
		while ( iternode.hasNext()) {
			Node node = (Node)iternode.next();
			if(!iteragent.hasNext()){
				System.err.println("Number of  agents and number of nodes in the habitat are incompabitble");
				break;
			}
			Agent agent = (Agent) iteragent.next();
			MapNodeToAgent.put(node, agent);
		
		}
		
		Vector<int[]> intmat= new Vector<int[]>();
		for (Iterator<Edge> iterator = edges.iterator(); iterator.hasNext();) {
			Edge edge = iterator.next();
			int []aedge = new int[]{ MapNodeToAgent.get(edge.getFrom()).getID(), MapNodeToAgent.get(edge.getTo()).getID()}; 
			intmat.add(aedge);
		}
		return intmat;
	}

}
